package com.vonchenchen.usbmuxd_android.usbmuxd.muxdprotocol;

import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbAccessory;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.util.Log;

import com.vonchenchen.usbmuxd_android.usbmuxd.Config;
import com.vonchenchen.usbmuxd_android.usbmuxd.localconn.ILocalConnector;
import com.vonchenchen.usbmuxd_android.usbmuxd.localconn.sharemem.AshmemDistributer;
import com.vonchenchen.usbmuxd_android.usbmuxd.localconn.socket.SocketDistributer;
import com.vonchenchen.usbmuxd_android.usbmuxd.muxdprotocol.protocol.UsbmuxdProtocol;
import com.vonchenchen.usbmuxd_android.usbmuxd.muxdprotocol.protocol.ProtocolParser;
import com.vonchenchen.usbmuxd_android.usbmuxd.usb.OnUSBConnStatusChanged;
import com.vonchenchen.usbmuxd_android.usbmuxd.usb.USBHelper;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import static android.media.CamcorderProfile.get;

/**
 * Created by lidechen on 2/25/17.
 */

public class SimpleTcpWrapper implements ISimpleTcpManager {

    private static final String TAG = "SimpleTcpWrapper";

    public static final String TCP_CONN_STATUS_CHANGE = "com.vonchenchen.usbmuxd_android.usbmuxd.muxdprotocol.tcp_state";

    public static final int DATA_PACKAGE_SIZE = 8201;

    private Context mContext;

    private Object mUploadLock;
    private Object mSendLock;

    /**
     * 用于解析和生成协议数据
     */
    private ProtocolParser mProtocolParser;
    /**
     * 数据通信对象引用
     */
    private USBHelper mConmunicateHelper;

    //private UsbmuxdProtocol.MuxConnection mMuxConnection;

    private OnRawDataReceiveListener mOnRawDataReceiveListener = null;

    private Thread mRecieveThread;
    private ReciveTask mReciveTask;

    private Thread mCameraThread;

    private Thread mSendInitThread;

    private OutputStream mCurrentDataInOutputStream;

    private static final int USB_LOST_PACKAGE_CNT = 3;
    /**
     * 记录usb丢包数量
     */
    private int mUSBLostCounter = 0;

    /**
     * 心跳包状态
     */
    private int mUSBHeartBeatState = UsbmuxdProtocol.TCP_DISCONNECTED;


    private int mTcpState = UsbmuxdProtocol.CONN_IDLE;

    private HashMap<Integer, UsbmuxdProtocol.MuxConnection> mConnMap;
    private HashMap<Integer, LocalConnectTask> mConnTaskMap;

    /**
     * 强制重启usb标志
     */
    private boolean mForceOpenUSB = false;


    private Thread mCheckThread;
    private CheckTask mCheckTask;

    public void addPort(Integer port) {

        UsbmuxdProtocol.MuxConnection muxConnection = new UsbmuxdProtocol.MuxConnection();
        muxConnection.state = UsbmuxdProtocol.CONN_IDLE;

        mConnMap.put(port, muxConnection);
    }

    public SimpleTcpWrapper(Context context) {

        mContext = context;

        mUploadLock = new Object();
        mSendLock = new Object();

        mConmunicateHelper = new USBHelper(mContext);

        //mMuxConnection = new UsbmuxdProtocol.MuxConnection();
        //mMuxConnection.state = UsbmuxdProtocol.CONN_IDLE;

        mProtocolParser = new ProtocolParser();

        mTcpState = UsbmuxdProtocol.CONN_IDLE;

        mConnMap = new HashMap<>();
        mConnTaskMap = new HashMap<>();

        mUSBLostCounter = 0;

        mUploadThreadLoopFlag = true;
        //start();
    }

    public void start(){
        //test
        //setUpClients();

        mCheckTask = new CheckTask();
        mCheckThread = new Thread(mCheckTask);
        mCheckThread.start();

        //数据传输层准备就绪 可以开启数据收发任务
        mConmunicateHelper.setOnDataTranPrepared(new USBHelper.OnDataTranPrepared() {
            @Override
            public void onDataTranPrepared(FileInputStream inputStream, FileOutputStream outputStream) {

                if (Config.DEBUG) {
                    Log.i(TAG, "accessory opened: inputStream " + inputStream + " outputStream " + outputStream);
                }

                //建立从usb读取数据的任务
                mReciveTask = new ReciveTask(inputStream);
                mRecieveThread = new Thread(mReciveTask);
                mRecieveThread.start();

                //                mSendTask = new SendTask(outputStream);
                //                mSendThead = new Thread(mSendTask);
                //                mSendThead.start();
            }
        });
    }

    private boolean mAndroidInitFlag = false;

    public void openUSBAsync(boolean reset) {

        if (mForceOpenUSB == false) {
            //            if (mMuxConnection.state != UsbmuxdProtocol.CONN_IDLE && !reSet) {
            //                return;
            //            }

            if(Config.DEBUG){
                Log.i(TAG, "openUSBAsync ... mUSBHeartBeatState "+mUSBHeartBeatState +" reset "+reset);
            }

            //状态为已连接且不是从后台进入 直接返回
            if (mUSBHeartBeatState != UsbmuxdProtocol.TCP_DISCONNECTED && !reset) {
                return;
            }

            if(Config.DEBUG){
                Log.i(TAG, "openUSBAsync ...");
            }

            //            if(!reset){    //如果是推后台后进入，则必然往后走
            //                return;
            //            }else if(mUSBHeartBeatState == UsbmuxdProtocol.TCP_CONNECTED){   //如果不是推后台，如果为连接状态则退出，为非连接状态则往后走
            //                return;
            //            }
        }

        mForceOpenUSB = false;

        //mMuxConnection = new UsbmuxdProtocol.MuxConnection();
        //mMuxConnection.state = UsbmuxdProtocol.CONN_IDLE;

        for (Map.Entry<Integer, UsbmuxdProtocol.MuxConnection> entry : mConnMap.entrySet()) {

            UsbmuxdProtocol.MuxConnection conn = entry.getValue();
            if (conn != null) {
                conn.reset();
            }
        }

        mConmunicateHelper.openAsync(new OnUSBConnStatusChanged() {
            @Override
            public void onUSBConnect(UsbAccessory accessory) {

                Log.i(TAG, "### onUSBConnect ###");

                mAndroidInitFlag = true;

                mSendInitThread = new Thread(new Runnable() {
                    @Override
                    public void run() {

                        while (mAndroidInitFlag) {

                            if(Config.DEBUG){
                                Log.i(TAG, "mSendInitThread loop");
                            }

                            sendAndroidInit();

                            try {
                                Thread.sleep(200);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });
                mSendInitThread.start();

            }

            @Override
            public void onUSBConnectFailed(UsbAccessory accessory) {

                Log.i(TAG, "### onUSBConnectFailed ###");

                mConmunicateHelper.close();
                mTcpState = UsbmuxdProtocol.CONN_IDLE;

                mForceOpenUSB = true;
            }

            @Override
            public void onUSBDisconnect(UsbAccessory accessory) {

                Log.i(TAG, "### onUSBDisconnect ###");

                mConmunicateHelper.close();
                mTcpState = UsbmuxdProtocol.CONN_IDLE;

                mForceOpenUSB = true;
            }
        });
    }

    public void closeUSB() {

        //通知复位连接状态
        //sendAndroidInit();

        mAndroidInitFlag = false;

        if (mRecieveThread != null) {
            mReadTaskRun = false;
            Thread.State state = mRecieveThread.getState();
            if (state == Thread.State.BLOCKED || state == Thread.State.TIMED_WAITING || state == Thread.State.TIMED_WAITING) {
                mRecieveThread.interrupt();
            }
            mRecieveThread = null;
        }

        mConmunicateHelper.close();
        mTcpState = UsbmuxdProtocol.CONN_IDLE;
    }

    public int getHartBeatState() {
        return mUSBHeartBeatState;
    }

    @Override
    public int readTcpData(byte[] data, int realLen) {

        UsbmuxdProtocol.MuxHeader header = mProtocolParser.parsePackageHeader(data, 0);

        switch (header.protocol) {

            case UsbmuxdProtocol.MUX_PROTO_ANDROIDINIT:

                mAndroidInitFlag = false;

                break;

            case UsbmuxdProtocol.MUX_PROTO_VERSION:
                if (header.length == UsbmuxdProtocol.MuxHeader.size + UsbmuxdProtocol.VersionHeader.size) {

                    if (Config.DEBUG) {
                        Log.i(TAG, "version protocol");
                    }

                    //返回数据
                    byte[] feedback = mProtocolParser.getVersionFeedbackData();

                    synchronized (mSendLock) {
                        mConmunicateHelper.writeSyncToUSB(feedback);
                    }

                    //mUSBHeartBeatState = UsbmuxdProtocol.TCP_CONNECTED;
                    mCheckTask.addVerionCounter();

                    mUSBLostCounter = 0;
                } else {
                    if (Config.DEBUG) {
                        Log.i(TAG, "error version protocol 2");
                    }

                    /*mUSBHeartBeatState = UsbmuxdProtocol.USB_DISCONNECTED;
                    mUSBLostCounter++;
                    //丢包数量大于限制，则认定usb断开
                    if (mUSBLostCounter > USB_LOST_PACKAGE_CNT) {
                        mUSBHeartBeatState = UsbmuxdProtocol.USB_DISCONNECTED;
                    }*/
                    return -1;
                }
                break;
            case UsbmuxdProtocol.MUX_PROTO_SETUP:
                if (Config.DEBUG) {
                    Log.i(TAG, "unsupported protocol");
                }
                break;
            case UsbmuxdProtocol.MUX_PROTO_TCP:

                if (Config.DEBUG) {
                    Log.i(TAG, "tcp protocol");
                }

                UsbmuxdProtocol.TcpHeader tcpHeader = mProtocolParser.parseTcpHeader(data, UsbmuxdProtocol.MuxHeader.size);

                int dport = 0x0000ffff & tcpHeader.th_dport;

                if (Config.DEBUG) {
                    Log.i(TAG, "tcpHeader th_sport " + tcpHeader.th_sport + " th_dport " + dport + " win " + tcpHeader.th_win + " sim " + tcpHeader.th_sum + " rx_ack " + (0xffffffff & tcpHeader.th_ack));
                    Log.i(TAG, "mMuxConnection get dport " + dport);
                }

                UsbmuxdProtocol.MuxConnection curMuxConnection = mConnMap.get(dport);
                if (curMuxConnection == null) {
                    if (Config.DEBUG) {
                        Log.i(TAG, "mMuxConnection get null");
                    }
                    return -1;
                }

                if (Config.DEBUG) {
                    Log.i(TAG, "mMuxConnection get success");
                }

                int payloadLength = realLen - UsbmuxdProtocol.MuxHeader.size - UsbmuxdProtocol.TcpHeader.size;
                int payloadOffset = UsbmuxdProtocol.MuxHeader.size + UsbmuxdProtocol.TcpHeader.size;

                deviceTcpInput(curMuxConnection, tcpHeader, data, payloadOffset, payloadLength);

                break;
            default:

                if (Config.DEBUG) {
                    byte[] tmp = new byte[8];
                    System.arraycopy(data, 0, tmp, 0, 8);
                    Log.i(TAG, "unkonw error protocol :" + header.protocol + " length :" + header.length + " " + Arrays.toString(tmp));
                    tmp = null;
                }

                return -1;
        }
        return 0;
    }

    private void deviceTcpInput(UsbmuxdProtocol.MuxConnection muxConnection, UsbmuxdProtocol.TcpHeader th, byte[] data, int payloadOffset, int payloadLength) {

        short sport = th.th_dport;
        short dport = th.th_sport;

        if (muxConnection.state == UsbmuxdProtocol.CONN_IDLE) {

            if ((th.th_flags & UsbmuxdProtocol.TH_SYN) != 0) {

                muxConnection.dport = dport;
                muxConnection.sport = sport;
                muxConnection.state = UsbmuxdProtocol.CONN_CONNECTING;
                muxConnection.last_ack_time = 0;
                muxConnection.max_payload = UsbmuxdProtocol.USB_MTU;
                muxConnection.rx_recvd = 0;
                muxConnection.tx_ack = 0;
                muxConnection.tx_sent = 0;
                muxConnection.tx_seq = 0;
                muxConnection.tx_win = UsbmuxdProtocol.USB_MTU;

            } else {
                if (Config.DEBUG) {
                    Log.i(TAG, "got data without client connection establish!");
                }
                return;
            }

        }

        muxConnection.rx_seq = th.th_seq;
        muxConnection.rx_ack = th.th_ack;
        muxConnection.rx_win = th.th_win << 8;

        if ((th.th_flags & UsbmuxdProtocol.TH_RST) != 0) {

            byte[] buf = new byte[payloadLength + 1];
            System.arraycopy(data, payloadOffset, buf, 0, payloadLength + 1);
            if (payloadLength != 0 && (buf[payloadLength - 1] == '\n')) {
                buf[payloadLength - 1] = 0;
            }
            buf[payloadLength] = 0;

            if (Config.DEBUG) {
                Log.i(TAG, "RTS reason: " + Arrays.toString(buf));
            }

            releaseClients();
        }

        if (muxConnection.state == UsbmuxdProtocol.CONN_CONNECTING) {

            muxConnection.tx_ack = 1;
            muxConnection.rx_recvd = muxConnection.rx_seq;

            if (sendUSBTcp(muxConnection, UsbmuxdProtocol.TH_ACK | UsbmuxdProtocol.TH_SYN, null, 0) < 0) {

                if (Config.DEBUG) {
                    int tmpSport = 0x0000ffff & sport;
                    int tmpDport = 0x0000ffff & dport;
                    Log.i(TAG, "Error sending TCP ACK to " + tmpSport + " -> " + tmpDport);
                }
                muxConnection.state = UsbmuxdProtocol.CONN_IDLE;
                return;
            }

            muxConnection.state = UsbmuxdProtocol.CONN_CONNECTED;
            if (Config.DEBUG) {
                Log.i(TAG, "state connenected");
            }

            //setUpClients();

        } else if (muxConnection.state == UsbmuxdProtocol.CONN_CONNECTED) {

            if (th.th_flags != UsbmuxdProtocol.TH_ACK) {
                if (Config.DEBUG) {
                    int tmpSport = 0x0000ffff & sport;
                    int tmpDport = 0x0000ffff & dport;
                    Log.i(TAG, "HardwareSocket Connection reset by " + tmpSport + "->" + tmpDport);
                }
                if ((th.th_flags & UsbmuxdProtocol.TH_RST) != 0) {
                    muxConnection.state = UsbmuxdProtocol.CONN_IDLE;
                }

                //重置连接
                resetConns();

                //Intent intent = new Intent();
                //intent.setAction(TCP_RESET);
                //mContext.sendBroadcast(intent);

            } else {
                if (payloadLength != 0) {

                    if (Config.DEBUG) {
                        Log.i(TAG, "payloadLength " + payloadLength);
                    }

                    connectionDeviceInput(muxConnection, data, payloadOffset, payloadLength);
                    if (muxConnection.tx_ack == muxConnection.rx_seq) {
                        muxConnection.tx_ack = muxConnection.rx_seq + payloadLength;

                        //TODO update lock
                        if (Config.DEBUG) {
                            Log.i(TAG, "prepare to send usb tcp len update lock1 lock");
                        }
                        synchronized (mUploadLock) {
                            if (Config.DEBUG) {
                                Log.i(TAG, "prepare to send usb tcp len update tx_sent " + payloadLength);
                            }
                            muxConnection.tx_sent = muxConnection.tx_seq - muxConnection.rx_ack;
                        }
                        if (Config.DEBUG) {
                            Log.i(TAG, "prepare to send usb tcp len update lock1 unlock");
                        }
                        //TODO update unlock
                    } else {
                        if (Config.DEBUG) {
                            Log.i(TAG, "tx data seq unmatch tx_ack " + muxConnection.tx_ack + " rx_seq " + muxConnection.rx_seq);
                        }
                    }
                    sendUSBTcpAck(muxConnection);

                } else {

                    //TODO update lock
                    if (Config.DEBUG) {
                        Log.i(TAG, "prepare to send usb tcp len update lock2 lock");
                    }
                    synchronized (mUploadLock) {
                        if (Config.DEBUG) {
                            Log.i(TAG, "update tx_sent " + muxConnection.tx_sent + ", tx_seq " + muxConnection.tx_seq + ", tx_ack " + muxConnection.tx_ack);
                        }
                        muxConnection.tx_sent = (muxConnection.tx_seq - muxConnection.rx_ack);
                        if (Config.DEBUG) {
                            Log.i(TAG, "after update " + muxConnection.tx_sent);
                        }
                    }
                    if (Config.DEBUG) {
                        Log.i(TAG, "prepare to send usb tcp len update lock2 unlock");
                    }
                    //TODO update unlock
                }
            }
        }
    }

    private void resetConns() {

        //复位所有muxConnection
        for (Map.Entry<Integer, UsbmuxdProtocol.MuxConnection> entry : mConnMap.entrySet()) {
            entry.getValue().state = UsbmuxdProtocol.CONN_IDLE;
        }

        //复位所有连接
        for (Map.Entry<Integer, LocalConnectTask> entry : mConnTaskMap.entrySet()) {
            entry.getValue().stopSocket();
        }
    }

    public void sendAndroidInit() {

        int len = UsbmuxdProtocol.MuxHeader.size + UsbmuxdProtocol.VersionHeader.size;
        byte[] data = new byte[len];

        UsbmuxdProtocol.MuxHeader header = new UsbmuxdProtocol.MuxHeader();
        header.protocol = UsbmuxdProtocol.MUX_PROTO_ANDROIDINIT;
        header.length = len;
        mProtocolParser.memsetMuxHeader(data, 0, header);

        UsbmuxdProtocol.VersionHeader versionHeader = new UsbmuxdProtocol.VersionHeader();
        versionHeader.major = UsbmuxdProtocol.VERSION;
        versionHeader.minor = 0;
        versionHeader.padding = 0;
        mProtocolParser.memsetVersionHeader(data, UsbmuxdProtocol.MuxHeader.size, versionHeader);

        //synchronized (mSendLock) {

        if (Config.DEBUG) {
            Log.i(TAG, "MUX_PROTO_ANDROID_INIT");
        }

        mConmunicateHelper.writeSyncToUSB(data);
        //}
    }

    private int sendUSBTcp(UsbmuxdProtocol.MuxConnection muxConnection, int flags, byte[] data, int length) {

        UsbmuxdProtocol.TcpHeader th = new UsbmuxdProtocol.TcpHeader();

        th.th_sport = (short) muxConnection.sport;
        th.th_dport = (short) muxConnection.dport;
        th.th_seq = muxConnection.tx_seq;
        th.th_ack = muxConnection.tx_ack;
        th.th_flags = (char) (flags & 0x000000ff);
        th.th_x2off = 5;
        th.th_win = (short) (muxConnection.tx_win >> 8);

        int res = 0;

        //TODO upload lock
        //byte[] thBuf = mProtocolParser.getTcpHeader(th);
        if (Config.DEBUG) {
            Log.i(TAG, "prepare to send usb tcp len update lock3 lock");
        }
        synchronized (mUploadLock) {

            if (Config.DEBUG) {
                int th_sport = 0x0000ffff & th.th_sport;
                int th_dport = 0x0000ffff & th.th_dport;
                Log.i(TAG, "[OUT] sport=" + th_sport + " dport=" + th_dport + " seq=" + th.th_seq + " ack=" + th.th_ack + " len" + length);
            }

            res = sendPacket(UsbmuxdProtocol.MUX_PROTO_TCP, th, data, length);
            if (res >= 0) {
                if ((flags & UsbmuxdProtocol.TH_SYN) != 0) {
                    muxConnection.tx_sent += 1;
                    muxConnection.tx_seq += 1;
                } else {
                    muxConnection.tx_sent += length;
                    muxConnection.tx_seq += length;
                    muxConnection.last_ack_time = mstime64();
                }
            }
        }
        if (Config.DEBUG) {
            Log.i(TAG, "prepare to send usb tcp len update lock3 unlock");
        }

        //TODO upload unlock
        return res;
    }

    private int sendPacket(int protocol, UsbmuxdProtocol.TcpHeader th, byte[] data, int length) {

        int hdrlen;
        int res;

        int totleLen;
        //TODO send lock
        if (Config.DEBUG) {
            Log.i(TAG, "prepare to send usb tcp len update send lock");
        }
        synchronized (mSendLock) {

            switch (protocol) {
                case UsbmuxdProtocol.MUX_PROTO_VERSION:

                    hdrlen = UsbmuxdProtocol.VersionHeader.size;
                    break;
                case UsbmuxdProtocol.MUX_PROTO_SETUP:

                    hdrlen = 0;
                    break;
                case UsbmuxdProtocol.MUX_PROTO_TCP:

                    hdrlen = UsbmuxdProtocol.TcpHeader.size;
                    break;
                default:
                    if (Config.DEBUG) {
                        Log.i(TAG, "Invalid protocol " + protocol + " for outgoing packet len " + length);
                    }
                    return -1;
            }

            totleLen = UsbmuxdProtocol.MuxHeader.size + hdrlen + length;
            if (totleLen > UsbmuxdProtocol.USB_MTU) {
                if (Config.DEBUG) {
                    Log.i(TAG, "Tried to send packet larger than USB MTU len " + length);
                }
                return -1;
            }
            byte[] buffer = new byte[totleLen];

            UsbmuxdProtocol.MuxHeader muxHeader = new UsbmuxdProtocol.MuxHeader();
            muxHeader.protocol = protocol;
            muxHeader.length = totleLen;

            mProtocolParser.memsetMuxHeader(buffer, 0, muxHeader);
            mProtocolParser.memsetTcpHeader(buffer, UsbmuxdProtocol.MuxHeader.size, th);

            if (length > 0) {
                System.arraycopy(data, 0, buffer, UsbmuxdProtocol.MuxHeader.size + hdrlen, length);
            }

            mConmunicateHelper.writeSyncToUSB(buffer);

            if (Config.DEBUG) {
                Log.i(TAG, "connecting write finish ... protocol " + protocol);
            }
        }
        if (Config.DEBUG) {
            Log.i(TAG, "prepare to send usb tcp len update send unlock");
        }
        //TODO send unlock
        return totleLen;
    }

    private long mstime64() {
        return System.currentTimeMillis();
    }

    private File mTargetFile = null;
    FileOutputStream mTargetFileOutputStream = null;

    /**
     * 获取数据
     *
     * @param conn
     * @param data
     * @param payloadOffset
     * @param payloadLength
     */
    private void connectionDeviceInput(UsbmuxdProtocol.MuxConnection conn, byte[] data, int payloadOffset, int payloadLength) {

        int sport = conn.sport & 0x0000ffff;

        mCurrentDataInOutputStream = mConnTaskMap.get(sport).getOutputStream();

        if (Config.DEBUG) {
            Log.i(TAG, "HardwareSocket payloadLength " + payloadLength + " CurrentDataInOutputStream " + mCurrentDataInOutputStream + " " + sport);
        }

        if (mCurrentDataInOutputStream != null) {

            long start = 0;
            if (Config.DEBUG) {
                start = System.currentTimeMillis();
                Log.i(TAG, "HardwareSocket payloadLength start ############");
            }

            try {
                mCurrentDataInOutputStream.write(data, payloadOffset, payloadLength);
                mCurrentDataInOutputStream.flush();

                //byte[] buf = new byte[1000];
                //mCameraDataInOutputStream.write(buf);
            } catch (IOException e) {
                //                e.printStackTrace();
            }

            if (Config.DEBUG) {
                long end = System.currentTimeMillis();
                Log.i(TAG, "HardwareSocket payloadLength finish ############ spend " + (end - start));
            }
        }

        //mSimpleSocketClient.sendAsync("Hello server".getBytes());
        //mSimpleSocketClient.sendAsync(data, payloadOffset, payloadLength);
    }

    private int sendUSBTcpAck(UsbmuxdProtocol.MuxConnection conn) {
        if (sendUSBTcp(conn, UsbmuxdProtocol.TH_ACK, null, 0) < 0) {
            if (Config.DEBUG) {
                Log.i(TAG, "Error sending TCP ACK " + conn.sport + "->" + conn.dport);
            }
            return -1;
        }
        return 0;
    }

    @Override
    public void writeRawData(byte[] data, int realLen) {
    }

    public void setOnRawDataReceiveListener(OnRawDataReceiveListener onRawDataReceiveListener) {
        mOnRawDataReceiveListener = onRawDataReceiveListener;
    }

    private boolean mUploadThreadLoopFlag = true;

    boolean mSetupClient = false;

    private LocalConnectTask mLocalConnectTask;

    /**
     * 建立本地socket客户端
     */
    public void setUpClients() {

//        if (!mSetupClient) {
//            mSetupClient = true;
//        } else {
//            return;
//        }

        if (Config.DEBUG) {
            Log.i(TAG, "prepare to setUpClients");
        }

        //mUploadThreadLoopFlag = true;

        /** 数据端口1 */
        //setupPort(55555, 3 * 1024 * 1024, -1);
        /** 数据端口2 */
        //setupPort(55560, 1024 * 500, 1024 * 500);
    }

    public void setupPort(int port, int sendBufSize, int receiveBufSize) {

        /** 创建端口号为port的 muxConnection*/
        UsbmuxdProtocol.MuxConnection muxConnection = new UsbmuxdProtocol.MuxConnection();
        muxConnection.state = UsbmuxdProtocol.CONN_IDLE;
        mConnMap.put(port, muxConnection);

        /** 创建端口号为port的本地连接任务 */
        LocalConnectTask localConnectTask = new LocalConnectTask(port, sendBufSize);
        if (receiveBufSize > 0) {
            localConnectTask.setReceiveBufferSize(receiveBufSize);
        }
        Thread thread = new Thread(localConnectTask);
        localConnectTask.setThread(thread);
        mConnTaskMap.put(port, localConnectTask);

        thread.start();
    }

    public ParcelFileDescriptor getParcelFileDescriptor(int port){

        LocalConnectTask task = mConnTaskMap.get(port);
        if(task.getLocalConnector() instanceof AshmemDistributer){
            return ((AshmemDistributer) task.getLocalConnector()).getParcelFileDescriptor();
        }
        return null;
    }

    private class LocalConnectTask implements Runnable {

        int mPort;

        //private Socket mSocket;
        private ILocalConnector mILocalConnector;

        private InputStream mSocketInput;
        private OutputStream mSocketOutput;

        private int mSocketBufSize;

        private boolean flag = true;

        private Thread mThread;

        private int mReceiveBufferSize = 0;

        private boolean mReadSocket = true;

        public void stopSocket() {
            //mReadSocket = false;
        }

        public ILocalConnector getLocalConnector(){
            return mILocalConnector;
        }

        public void setReceiveBufferSize(int size) {
            mReceiveBufferSize = size;
        }

        public void setThread(Thread thread) {
            mThread = thread;
        }

        public LocalConnectTask(int port, int socketSendBufSize) {
            mPort = port;
            mSocketBufSize = socketSendBufSize;
        }

        public OutputStream getOutputStream() {
            return mSocketOutput;
        }

        @Override
        public void run() {

            UsbmuxdProtocol.MuxConnection muxConnection = mConnMap.get(mPort);
            //UsbmuxdProtocol.MuxConnection muxConnection = mMuxConnection;

            while (true) {

                //byte[] buffer = new byte[8201 * 1];
                byte[] buffer = new byte[DATA_PACKAGE_SIZE * 1];

                try {

                    if (Config.DEBUG) {
                        Log.i(TAG, mPort + " LocalConnectTask start socket ...");
                    }

                    if (mILocalConnector != null) {
                        mILocalConnector.close();
                    }

                    mILocalConnector = new SocketDistributer("127.0.0.1", mPort);
                    mILocalConnector.setSendBufferSize(mSocketBufSize);
                    mILocalConnector.setReceiveBufferSize(mReceiveBufferSize);
                    mILocalConnector.open();

                    mSocketInput = mILocalConnector.getInputStream();
                    mSocketOutput = mILocalConnector.getOutputStream();

                    mReadSocket = true;

                    int totleLen = 0;
                    int len = 0;

                    while (true) {

                        while ((len = mSocketInput.read(buffer)) != -1 && mReadSocket) {

                            totleLen += len;
                            totleLen -= 10;

                            if (Config.DEBUG) {

                                //Log.i(TAG, "port "+mPort+"mCameraThread send tcp " + Arrays.toString(buffer));

                                Log.i(TAG, mPort + " LocalConnectTask tx_sent " + muxConnection.tx_sent + " read len " + len + " sum " + (muxConnection.tx_sent + len) + " rx_win " + muxConnection.rx_win);
                                Log.i(TAG, mPort + " LocalConnectTask totleLen " + totleLen);
                            }

                            int cnt = 0;
                            while (muxConnection.tx_sent + len > muxConnection.rx_win) {
                                try {
                                    cnt++;
                                    Thread.sleep(1);
                                    if (Config.DEBUG) {
                                        Log.i(TAG, mPort + "LocalConnectTask sleep ... muxConnection.tx_sent " + muxConnection.tx_sent + " muxConnection.rx_win " + muxConnection.rx_win);
                                    }
                                    if (cnt > 1000) {
                                        //break;
                                    }
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                            if (cnt > 1000) {

                            }

                            if (Config.DEBUG) {
                                Log.i(TAG, mPort + " LocalConnectTask new tx_sent " + muxConnection.tx_sent + " read len " + len + " sum " + (muxConnection.tx_sent + len) + " rx_win " + muxConnection.rx_win);
                                Log.i(TAG, mPort + " LocalConnectTask send xxxxxx ");
                                Log.i(TAG, mPort + " LocalConnectTask send data " + Arrays.toString(buffer));
                            }
                            sendUSBTcp(muxConnection, UsbmuxdProtocol.TH_ACK, buffer, len);

                            if (mPort == 55560) {
                                Thread.sleep(12);
                            } else {
                                Thread.sleep(5);
                            }
                            //test
                            //Thread.sleep(60);

                            if (Config.DEBUG) {
                                Log.i(TAG, mPort + " LocalConnectTask finish xxxxxx ");
                            }
                        }
                        Thread.sleep(600);
                    }

                } catch (Exception e) {
                    //                    e.printStackTrace();

                    /*if (mSocket != null) {
                        try {
                            mSocket.close();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                    }*/
                    if (mILocalConnector != null) {
                        try {
                            mILocalConnector.close();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                    }

                    if (Config.DEBUG) {
                        Log.i(TAG, " LocalConnectTask conn " + mPort + " time out ... ");
                    }
                }
            }
        }
    }

    /**
     * 释放本地socket客户端
     */
    private void releaseClients() {
        //        closeUSB();
/*        if(Config.DEBUG){
            Log.i(TAG, "prepare to release Clients");
        }

        if(mCameraThread != null) {

            Thread.State state = mCameraThread.getState();
            if(state == Thread.State.BLOCKED || state == Thread.State.WAITING || state == Thread.State.TIMED_WAITING){
                mCameraThread.interrupt();
            }

            mUploadThreadLoopFlag = false;

            mCameraThread = null;
        }*/
    }

    private byte[] mReciveBuffer;
    private static final int RECIVE_BUF_SIZE = UsbmuxdProtocol.USB_MTU;//1024*10;
    private boolean mReadTaskRun = false;

    public class ReciveTask implements Runnable {

        private FileInputStream mInputStream;

        public ReciveTask(FileInputStream inputStream) {

            mInputStream = inputStream;
        }

        @Override
        public void run() {

            mReciveBuffer = new byte[RECIVE_BUF_SIZE];

            mReadTaskRun = true;

            int off = 0;
            int len = 0;

            while (mReadTaskRun) {
                try {

                    if (Config.DEBUG) {
                        Log.i(TAG, "accessory opened start read");
                    }

                    int ret = mInputStream.read(mReciveBuffer, off, RECIVE_BUF_SIZE - off);

                    if (Config.DEBUG) {
                        Log.i(TAG, "accessory opened read ok");
                        Log.i(TAG, "  ret " + ret + " off " + off);
                    }

                    if (ret >= 0) {

                        off += ret;

                        while (off >= UsbmuxdProtocol.MuxHeader.size) {

                            if ((len = getInt(mReciveBuffer, 4)) <= off) {

                                if (Config.DEBUG) {
                                    Log.i(TAG, "ReciveTask prepare to handle len " + len + " off " + off);
                                }

                                readTcpData(mReciveBuffer, len);
                                off -= len;
                                System.arraycopy(mReciveBuffer, len, mReciveBuffer, 0, off);

                                if (Config.DEBUG) {
                                    Log.i(TAG, "ReciveTask end to handle " + " off " + off);
                                }
                            } else {
                                break;
                            }
                        }

                    } else {
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                } catch (IOException e) {
                    //                    e.printStackTrace();

                    if (Config.DEBUG) {
                        Log.i(TAG, "ReciveTask exception :\n" + e.toString());
                    }

                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e1) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private Handler mSendHandler = null;

    private byte[] mSendBuffer;
    private static final int SEND_BUF_SIZE = 1024 * 10;
    private boolean mSendTaskRun = false;

/*    public class SendTask implements Runnable {

        private FileOutputStream mOutputStream;

        public SendTask(FileOutputStream outputStream) {

            mOutputStream = outputStream;
            mSendBuffer = new byte[SEND_BUF_SIZE];
        }

        @Override
        public void run() {

            Looper.prepare();

            mSendHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {

                    int len = msg.what;

                    mConmunicateHelper.writeSyncToUSB(mReciveBuffer, 0, len);
                    Arrays.fill(mReciveBuffer, 0, len, (byte) 0);

                    if (Config.DEBUG) {
                        Log.i(TAG, " send " + len);
                    }
                }
            };

            Looper.loop();
        }
    }*/

    /**
     * 定时检测心跳状态
     */
    private class CheckTask implements Runnable {

        /**
         * 记录收到心跳包的数量
         */
        public int mUSBVerionCounter = 0;
        /**
         * 保存上一次mUSBVerionCounter的值
         */
        private int mUSBVerionCounterRec = mUSBVerionCounter;

        private int mStatusRec = mUSBHeartBeatState;

        private Intent mIntent;

        public CheckTask() {
            mIntent = new Intent();
            mIntent.setAction(TCP_CONN_STATUS_CHANGE);
        }

        public void addVerionCounter() {
            synchronized (CheckTask.class) {
                mUSBVerionCounter++;
            }
        }

        @Override
        public void run() {

            while (true) {
                try {
                    Thread.sleep(700);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                if (Config.DEBUG) {
                    //Log.i(TAG, "mUSBVerionCounter " + mUSBVerionCounter);
                }

                synchronized (CheckTask.class) {
                    if (mUSBVerionCounter > mUSBVerionCounterRec) {

                        mUSBHeartBeatState = UsbmuxdProtocol.TCP_CONNECTED;
                        mUSBVerionCounterRec = mUSBVerionCounter;
                    } else {

                        mUSBHeartBeatState = UsbmuxdProtocol.TCP_DISCONNECTED;
                        mUSBVerionCounterRec = 0;
                        mUSBVerionCounter = 0;
                    }

                    //if(mStatusRec != mUSBHeartBeatState){
                    mIntent.putExtra("USBHeartBeatState", mUSBHeartBeatState);
                    mContext.sendBroadcast(mIntent);
                    mStatusRec = mUSBHeartBeatState;
                    //}
                }
            }
        }
    }

    private USBHelper.OnUSBDataRTStatusChangedListener mOnUSBDataRTStatusChangedListener = null;

    private void setInt(byte[] buffer, int offset, int data) {
        buffer[offset] = (byte) (0x000000ff & data);
        buffer[offset + 1] = (byte) ((0x0000ff00 & data) >> 8);
        buffer[offset + 2] = (byte) ((0x00ff0000 & data) >> 16);
        buffer[offset + 3] = (byte) ((0xff000000 & data) >> 24);
    }

    //大端
    private int getInt(byte[] data, int offset) {

        int ret = 0;

        //ret = ret | data[3+offset] | data[2+offset]<<8 | data[1+offset]<<16 | data[0+offset]<<24;
        ret = ret | ((data[3 + offset]) & 0x000000ff) | ((data[2 + offset] << 8) & 0x0000ff00) | ((data[1 + offset] << 16) & 0x00ff0000) | ((data[0 + offset] << 24) & 0xff000000);

        return ret;
    }
}
